package com.acooly.module.openapi.client.provider.cj.utils;

import com.acooly.module.openapi.client.provider.cj.message.CjBatchDeductRequest;
import com.acooly.module.openapi.client.provider.cj.message.CjBatchQueryRequest;
import com.acooly.module.openapi.client.provider.cj.message.CjRealDeductRequest;
import com.acooly.module.openapi.client.provider.cj.message.CjRealQueryRequest;
import com.acooly.module.openapi.client.provider.cj.message.dto.CjBatchRetInfo;
import com.acooly.module.openapi.client.provider.cj.message.dto.CjDeductBodyInfo;

import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;

/**
 * @author fufeng 2017/12/7 17:21.
 */
@Slf4j
public class XmlHelper {

    public static String formatXml_UTF8(Document doc) {
        try {
            OutputFormat format = OutputFormat.createPrettyPrint();
            format.setEncoding("UTF-8");
            format.setIndent(false);
            format.setNewlines(false);
            format.setNewLineAfterDeclaration(false);
			/*
			format.setLineSeparator("\n");
			 */
            StringWriter out = new StringWriter();
            XMLWriter writer = new XMLWriter(out, format);
            writer.write(doc);
            writer.close();
            return out.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }//method


    /**
     * -------------------------changjie实时代扣--------------------------------
     * @param data
     * @return
     */
    public static String buildCjRealMsg(CjRealDeductRequest data) {
        Document doc = DocumentHelper.createDocument();
        Element msgEl = doc.addElement("MESSAGE");

        Element infoEl = msgEl.addElement("INFO");
        infoEl.addElement("TRX_CODE").setText(StringHelper.nvl(data.getTrxCode()));
        infoEl.addElement("VERSION").setText(StringHelper.nvl(data.getVersion()));
        infoEl.addElement("MERCHANT_ID").setText(StringHelper.nvl(data.getMertid()));
        infoEl.addElement("REQ_SN").setText(StringHelper.nvl(data.getReqSn()));
        infoEl.addElement("TIMESTAMP").setText(StringHelper.getCurrentTimestamp());
        infoEl.addElement("SIGNED_MSG").setText("");

        Element bodyEl = msgEl.addElement("BODY");
        bodyEl.addElement("BUSINESS_CODE").setText(StringHelper.nvl(data.getBusinessCode()));
        bodyEl.addElement("CORP_ACCT_NO").setText(StringHelper.nvl(data.getCorpAccNo()));
        bodyEl.addElement("PRODUCT_CODE").setText(StringHelper.nvl(data.getProductCode()));
        bodyEl.addElement("ACCOUNT_PROP").setText(StringHelper.nvl(data.getAccountProp()));
        bodyEl.addElement("SUB_MERCHANT_ID").setText(StringHelper.nvl(data.getSubMertid()));
        bodyEl.addElement("BANK_GENERAL_NAME").setText(StringHelper.nvl(data.getBankGeneralName()));
        bodyEl.addElement("ACCOUNT_TYPE").setText(StringHelper.nvl(data.getAccountType()));
        bodyEl.addElement("ACCOUNT_NO").setText(StringHelper.nvl(data.getAccountNo()));
        bodyEl.addElement("ACCOUNT_NAME").setText(StringHelper.nvl(data.getAccountName()));
        bodyEl.addElement("PROVINCE").setText(StringHelper.nvl(data.getProvince()));
        bodyEl.addElement("CITY").setText(StringHelper.nvl(data.getCity()));
        bodyEl.addElement("BANK_NAME").setText(StringHelper.nvl(data.getBankName()));
        bodyEl.addElement("BANK_CODE").setText(StringHelper.nvl(data.getBankCode()));
        bodyEl.addElement("DRCT_BANK_CODE").setText(StringHelper.nvl(data.getDrctBankCode()));
        bodyEl.addElement("PROTOCOL_NO").setText(StringHelper.nvl(data.getProtocolNo()));
        bodyEl.addElement("CURRENCY").setText(StringHelper.nvl(data.getCurrency()));
        bodyEl.addElement("AMOUNT").setText(StringHelper.nvl(data.getAmount()));
        bodyEl.addElement("ID_TYPE").setText(StringHelper.nvl(data.getIdType()));
        bodyEl.addElement("ID").setText(StringHelper.nvl(data.getId()));
        bodyEl.addElement("TEL").setText(StringHelper.nvl(data.getTel()));
        bodyEl.addElement("CORP_FLOW_NO").setText(StringHelper.nvl(data.getCorpFlowNo()));
        bodyEl.addElement("SUMMARY").setText(StringHelper.nvl(data.getSummary()));
        bodyEl.addElement("POSTSCRIPT").setText(StringHelper.nvl(data.getPostscript()));
        String xml = formatXml_UTF8(doc);
        return xml;
    }//method


    /**
     *
     * @param cjRespmsg
     * @param messageMap
     * @throws Exception
     */
    public static void parseCjRealMsgToDto(String cjRespmsg, Map<String, Object> messageMap) throws Exception {
        Document reqDoc = DocumentHelper.parseText(cjRespmsg);

        Element msgEl = reqDoc.getRootElement();
        Element infoEl = msgEl.element("INFO");

        messageMap.put("retCode",infoEl.elementText("RET_CODE"));
        messageMap.put("errMsg",infoEl.elementText("ERR_MSG"));
        messageMap.put("timestamp",infoEl.elementText("TIMESTAMP"));

        Element bodyEl = msgEl.element("BODY");
        if (bodyEl == null) {
            return;
        }
        messageMap.put("status",bodyEl.elementText("RET_CODE"));
        messageMap.put("detail",bodyEl.elementText("RET_MSG"));
        messageMap.put("errCode",bodyEl.elementText("ERR_CODE"));
        messageMap.put("errDetail",bodyEl.elementText("ERR_MSG"));
    }//method



    /**
     * -------------------------changjie批量代扣--------------------------------
     * @param data
     * @return
     */
    public static String buildCjBatchMsg(CjBatchDeductRequest data) {
        Document doc = DocumentHelper.createDocument();
        Element msgEl = doc.addElement("MESSAGE");

        Element infoEl = msgEl.addElement("INFO");
        infoEl.addElement("TRX_CODE").setText(StringHelper.nvl(data.getTrxCode()));
        infoEl.addElement("VERSION").setText(StringHelper.nvl(data.getVersion()));
        infoEl.addElement("MERCHANT_ID").setText(StringHelper.nvl(data.getMertid()));
        infoEl.addElement("REQ_SN").setText(StringHelper.nvl(data.getReqSn()));
        infoEl.addElement("TIMESTAMP").setText(StringHelper.getCurrentTimestamp());
        infoEl.addElement("SIGNED_MSG").setText("");

        Element bodyEl = msgEl.addElement("BODY");

        Element batch = bodyEl.addElement("BATCH");
        batch.addElement("BUSINESS_CODE").setText(StringHelper.nvl(data.getBusinessCode()));
        batch.addElement("CORP_ACCT_NO").setText(StringHelper.nvl(data.getCorpAccNo()));
        batch.addElement("PRODUCT_CODE").setText(StringHelper.nvl(data.getProductCode()));
        batch.addElement("ACCOUNT_PROP").setText(StringHelper.nvl(data.getAccountProp()));
        batch.addElement("SUB_MERCHANT_ID").setText(StringHelper.nvl(data.getSubMertid()));
        batch.addElement("TIMELINESS").setText(StringHelper.nvl(data.getTimeliness()));
        batch.addElement("APPOINTMENT_TIME").setText(StringHelper.nvl(data.getAppointmentTime()));
        batch.addElement("TOTAL_CNT").setText(StringHelper.nvl(data.getTotalCnt()));
        batch.addElement("TOTAL_AMT").setText(StringHelper.nvl(data.getTotalAmt().getCent()+""));
        Element detailTitle = bodyEl.addElement("TRANS_DETAILS");

        for (CjDeductBodyInfo body : data.getCjDeductBodyInfos()) {
            Element dtl = detailTitle.addElement("DTL");
            dtl.addElement("SN").setText(StringHelper.nvl(body.getBizOrderNo()));
            dtl.addElement("BANK_GENERAL_NAME").setText(StringHelper.nvl(body.getBankGeneralName()));
            dtl.addElement("ACCOUNT_TYPE").setText("");
            dtl.addElement("ACCOUNT_NO").setText(StringHelper.nvl(body.getPayBankCardNo()));
            dtl.addElement("ACCOUNT_NAME").setText(StringHelper.nvl(body.getPayRealName()));
            dtl.addElement("PROVINCE").setText(StringHelper.nvl(body.getPayBankProvince()));
            dtl.addElement("CITY").setText(StringHelper.nvl(body.getPayBankCity()));
            dtl.addElement("BANK_NAME").setText(StringHelper.nvl(body.getPayBankName()));
            dtl.addElement("BANK_CODE").setText(StringHelper.nvl(body.getPayBankUnionNo()));
            dtl.addElement("DRCT_BANK_CODE").setText(StringHelper.nvl(body.getDrctBankCode()));
            dtl.addElement("CURRENCY").setText(StringHelper.nvl(body.getCurrency()));
            dtl.addElement("AMOUNT").setText(StringHelper.nvl(body.getAmount().getCent()+""));
            dtl.addElement("PROTOCOL_NO").setText(StringHelper.nvl(body.getProtocolNo()));
            dtl.addElement("ID_TYPE").setText(StringHelper.nvl(""));
            dtl.addElement("ID").setText(StringHelper.nvl(body.getPayCertNo()));
            dtl.addElement("TEL").setText(StringHelper.nvl(body.getPayMobileNo()));
        }//for

        String xml = formatXml_UTF8(doc);

        return xml;
    }//method


    /**
     *
     * @param cjRespmsg
     * @param messageMap
     * @throws Exception
     */
    public static void parseCjBatchMsgToDto(String cjRespmsg, Map<String, Object> messageMap) throws Exception {
        Document reqDoc = DocumentHelper.parseText(cjRespmsg);

        Element msgEl = reqDoc.getRootElement();
        Element infoEl = msgEl.element("INFO");

        messageMap.put("retCode",infoEl.elementText("RET_CODE"));
        messageMap.put("errMsg",infoEl.elementText("ERR_MSG"));

        //得到根节点下的body节点
        Element bodyEl = msgEl.element("BODY");
        if (bodyEl == null) {
            return;
        }
        //得到body节点下的TRANS_DETAILS节点
        Element detailsEl = bodyEl.element("TRANS_DETAILS");
        //得到TRANS_DETAILS节点下的DTL节点
        Iterator dtlIter = detailsEl.elementIterator("DTL");

        List<CjBatchRetInfo> btds = new ArrayList<CjBatchRetInfo>();
        // 遍历body节点
        while (dtlIter.hasNext()) {
            Element dtlEle = (Element) dtlIter.next();
            CjBatchRetInfo bodyTransDetail = new CjBatchRetInfo();
            bodyTransDetail.setBizOrderNo(dtlEle.elementTextTrim("SN"));
            bodyTransDetail.setRetCode(dtlEle.elementTextTrim("RET_CODE"));
            bodyTransDetail.setErrMsg(dtlEle.elementTextTrim("ERR_MSG"));
            btds.add(bodyTransDetail);
        }
        messageMap.put("batchRetDetils",btds);
    }//method

    /**
     * 单笔代扣查询
     * @param request
     * @return
     */
    public static String buildRealQueryMsg(CjRealQueryRequest request) {
        Document doc = DocumentHelper.createDocument();
        Element msgEl = doc.addElement("MESSAGE");

        Element infoEl = msgEl.addElement("INFO");
        infoEl.addElement("TRX_CODE").setText(StringHelper.nvl(request.getTrxCode()));
        infoEl.addElement("VERSION").setText(StringHelper.nvl(request.getVersion()));
        infoEl.addElement("MERCHANT_ID").setText(StringHelper.nvl(request.getMertid()));
        infoEl.addElement("REQ_SN").setText(StringHelper.nvl(request.getReqSn()));
        infoEl.addElement("TIMESTAMP").setText(StringHelper.getCurrentTimestamp());
        infoEl.addElement("SIGNED_MSG").setText("");

        Element bodyEl = msgEl.addElement("BODY");
        bodyEl.addElement("QRY_REQ_SN").setText(StringHelper.nvl(request.getQryReqSn()));

        String xml = formatXml_UTF8(doc);
        return xml;
    }//method


    /**
     *
     * @param cjRespmsg
     * @param messageMap
     * @throws Exception
     */
    public static void parseRealQueryMsgToDto(String cjRespmsg, Map<String, Object> messageMap) throws Exception {
        Document reqDoc = DocumentHelper.parseText(cjRespmsg);

        Element msgEl = reqDoc.getRootElement();
        Element infoEl = msgEl.element("INFO");

        messageMap.put("retCode",infoEl.elementText("RET_CODE"));
        messageMap.put("errMsg",infoEl.elementText("ERR_MSG"));
        messageMap.put("timestamp",infoEl.elementText("TIMESTAMP"));

        Element bodyEl = msgEl.element("BODY");
        if (bodyEl == null) {
            return;
        }

        messageMap.put("charge",bodyEl.elementText("CHARGE"));
        messageMap.put("corpAcctNo",bodyEl.elementText("CORP_ACCT_NO"));
        messageMap.put("corpAcctName",bodyEl.elementText("CORP_ACCT_NAME"));
        messageMap.put("accountNo",bodyEl.elementText("ACCOUNT_NO"));
        messageMap.put("accountName",bodyEl.elementText("ACCOUNT_NAME"));
        messageMap.put("amount",bodyEl.elementText("AMOUNT"));
        messageMap.put("summary",bodyEl.elementText("SUMMARY"));
        messageMap.put("corpFlowNo",bodyEl.elementText("CORP_FLOW_NO"));
        messageMap.put("postscript",bodyEl.elementText("POSTSCRIPT"));
        messageMap.put("status",bodyEl.elementText("RET_CODE"));
        messageMap.put("detail",bodyEl.elementText("ERR_MSG"));

    }//method


    /**
     * CJ批量结果查询
     * @param request
     * @return
     */
    public static String buildBatchQueryMsg(CjBatchQueryRequest request) {
        Document doc = DocumentHelper.createDocument();
        Element msgEl = doc.addElement("MESSAGE");

        Element infoEl = msgEl.addElement("INFO");
        infoEl.addElement("TRX_CODE").setText(StringHelper.nvl(request.getTrxCode()));
        infoEl.addElement("VERSION").setText(StringHelper.nvl(request.getVersion()));
        infoEl.addElement("MERCHANT_ID").setText(StringHelper.nvl(request.getMertid()));
        infoEl.addElement("REQ_SN").setText(StringHelper.nvl(request.getReqSn()));
        infoEl.addElement("TIMESTAMP").setText(StringHelper.getCurrentTimestamp());
        infoEl.addElement("SIGNED_MSG").setText("");

        Element bodyEl = msgEl.addElement("BODY");
        bodyEl.addElement("QRY_REQ_SN").setText(StringHelper.nvl(request.getQryReqSn()));

        if (StringUtils.isNotBlank(request.getSn())) {
            Element dtls = bodyEl.addElement("TRANS_DETAILS");
            String[] snArray = request.getSn().split(",");
            for (String sn : snArray) {
                dtls.addElement("SN").setText(sn);
            }
        }//if
        String xml = formatXml_UTF8(doc);
        return xml;
    }//method


    /**
     *
     * @param cjRespmsg
     * @param messageMap
     * @throws Exception
     */
    public static void parseBatchQueryMsgToDto(String cjRespmsg, Map<String, Object> messageMap) throws Exception {
        Document reqDoc = DocumentHelper.parseText(cjRespmsg);

        Element msgEl = reqDoc.getRootElement();
        Element infoEl = msgEl.element("INFO");

        messageMap.put("retCode",infoEl.elementText("RET_CODE"));
        messageMap.put("errMsg",infoEl.elementText("ERR_MSG"));
        messageMap.put("timestamp",infoEl.elementText("TIMESTAMP"));

        Element bodyEl = msgEl.element("BODY");
        if (bodyEl == null) {
            return;
        }
        Element details = bodyEl.element("TRANS_DETAILS");
        Element dtl = details.element("DTL");

        messageMap.put("charge",dtl.elementText("CHARGE"));
        messageMap.put("corpAcctNo",dtl.elementText("CORP_ACCT_NO"));
        messageMap.put("corpAcctName",dtl.elementText("CORP_ACCT_NAME"));
        messageMap.put("accountNo",dtl.elementText("ACCOUNT_NO"));
        messageMap.put("accountName",dtl.elementText("ACCOUNT_NAME"));
        messageMap.put("amount",dtl.elementText("AMOUNT"));
        messageMap.put("summary",dtl.elementText("SUMMARY"));
        messageMap.put("corpFlowNo",dtl.elementText("CORP_FLOW_NO"));
        messageMap.put("postscript",dtl.elementText("POSTSCRIPT"));
        messageMap.put("status",dtl.elementText("RET_CODE"));
        messageMap.put("detail",dtl.elementText("ERR_MSG"));
    }//method

}
